class MyPromise {
  /* Promise状态定义 */
  static STATUS_PENDING = 0; // 挂起态
  static STATUS_FULFILLED = 1; // 履约态
  static STATUS_REJECTED = 2; // 毁约态

  constructor(executor) {
    /* 回调队列 + 回调入参 （JS单线程模型=每次只能有一个回调被执行） */
    this.callbacks = [];
    this.cbArg = null;

    /* 绑定执行器函数中的resolve与reject */
    this.executor = executor.bind(
      this, //当前promise实例

      //当前promise实例执行resolve时,this不变
      MyPromise.doResolve.bind(this),

      //当前promise实例执行reject时,this不变
      MyPromise.doReject.bind(this)
    );

    // 执行任务前先将Promise状态设置为pending
    this.status = MyPromise.STATUS_PENDING;

    // 执行任务（任务中会resolve/doResolve或reject/doReject）
    this.executor();
  }

  /* promise实例执行resolve */
  static doResolve(data) {
    /* 设置状态为履约态 + 设置回调时的入参 + 拉起下一次回调 */
    this.status = MyPromise.STATUS_FULFILLED;
    this.cbArg = data;

    // 拉起下一次then回调
    setTimeout(() => {
      this.next();
    });
  }

  /* promise实例执行reject */
  static doReject(err) {
    /* 设置状态为毁约态 + 设置回调时的错误 + 拉起下一次回调 */
    this.status = MyPromise.STATUS_REJECTED;
    this.cbArg = err;

    // 拉起下一次catch回调
    setTimeout(() => {
      this.next();
    });
  }

  /* 
    成功时：从回调队列头部把所有的catch驱逐
    失败时：从回调队列头部把所有的then驱逐
    */
  shiftCallbacksWithType(type) {
    while (this.callbacks.length && this.callbacks[0].type === type) {
      // 驱逐一个回调函数
      this.callbacks.shift();
    }
  }

  /* 
    从回调队列里拉取下一个适当的callback并回调之
    这是MyPromise的核心代码：递归inside! 
    */
  next() {
    /* 确定该回调哪一个callback */
    if (this.status === MyPromise.STATUS_FULFILLED) {
      // 履约时：弹光队列头部的catch回调
      this.shiftCallbacksWithType("catch");
    }

    if (this.status === MyPromise.STATUS_REJECTED) {
      // 毁约时：弹光队列头部的then回调
      this.shiftCallbacksWithType("then");
    }

    /* 如果回调队列已空，则直接结束程序 */
    if (!this.callbacks.length) {
      console.log("回调队列已空");
      return;
    }

    /* 拉取回调队列头部的回调函数（注意这里无视了type只解构出函数本身） */
    let { callback } = this.callbacks.shift();

    /* 防止回调函数中throw错误 */
    try {
      // 执行回调并拿到其结果（value或promise对象）
      let value = callback(this.cbArg);

      // 如果回调函数返回一个value 继续向下resolve(value)
      if (!(value instanceof MyPromise)) {
        MyPromise.doResolve.call(this, value);
      } else {
        // 如果回调函数返回一个Promise对象
        // 为后续所有callback悄悄置换this为新的Promise对象
        // 这里特别注意：
        // Promise对象的执行器很快就要执行起来了！因为构造器里有setTimeout(executor,0)！
        value.callbacks = this.callbacks;
        // result.callbacks = this.callbacks.map(({ type, callback }) => ({
        //     type,
        //     callback: callback.bind(result),
        // }));
      }
    } catch (err) {
      // 回调函数抛出错误时相当于reject(err)
      MyPromise.doReject.call(this, err);
    }
  }

  /* 语法糖：创建一个立即resolve的Promise对象 */
  static resolve(data) {
    return new MyPromise((resolve) => resolve(data));
  }

  /* 语法糖：创建一个立即reject的Promise对象 */
  static reject(err) {
    return new MyPromise((resolve, reject) => reject(err));
  }

  /* 收集成功回调到队列 */
  then(onData) {
    // 将来一旦Promise毁约 回调队列头部的所有then回调都要弹出作废
    this.callbacks.push({ type: "then", callback: onData });
    return this;
  }

  /* 收集失败回调到队列 */
  catch(onErr) {
    // 将来一旦Promise履约 回调队列头部的所有catch回调都要弹出作废
    this.callbacks.push({ type: "catch", callback: onErr });
    return this;
  }

  /* 收集终点回调到队列（此处假设只有一个终点回调） */
  finally(onFinish) {
    this.callbacks.push({ type: "finally", callback: onFinish });
    return this;
  }
}

module.exports = MyPromise;
